//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_api_serv

import (
	"context"
	"sort"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type ProjectApiImpl struct {
	project_api.UnimplementedProjectApiServer
}

func (apiImpl *ProjectApiImpl) Create(ctx context.Context, req *project_api.CreateRequest) (*project_api.CreateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.CreateResponse{
			Code:   project_api.CreateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	projectId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = api_common.AddProject(sessCtx, projectId, req.BasicInfo.ProjectName, req.BasicInfo.ProjectDesc, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_api.CreateResponse{
			Code:      project_api.CreateResponse_CODE_OK,
			ProjectId: projectId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//add event
	go apiImpl.addCreateEvent(sessionItem, req, projectId, nowTime)
	//send notice
	go api_common.SendNoticeToProjectScope(context.Background(), projectId, &notices_project.AddMemberNotice{
		ProjectId:    projectId,
		MemberUserId: sessionItem.UserId,
	})
	return ret.(*project_api.CreateResponse), nil
}

func (apiImpl *ProjectApiImpl) Update(ctx context.Context, req *project_api.UpdateRequest) (*project_api.UpdateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.UpdateResponse{
			Code:   project_api.UpdateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.UpdateResponse{
			Code:   project_api.UpdateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.UpdateResponse{
			Code:   project_api.UpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if projectItem.Closed {
		return &project_api.UpdateResponse{
			Code:   project_api.UpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_api.UpdateResponse{
			Code:   project_api.UpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//更新信息
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ProjectInfoDao.UpdateBasicInfo(sessCtx, req.ProjectId, &project_dao.BasicProjectInfoDbItem{
			ProjectName: req.BasicInfo.ProjectName,
			ProjectDesc: req.BasicInfo.ProjectDesc,
		})
		if err != nil {
			return nil, err
		}

		return &project_api.UpdateResponse{
			Code: project_api.UpdateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	go apiImpl.addUpdateEvent(sessionItem, req, projectItem)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateProjectNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_api.UpdateResponse), nil
}

func (apiImpl *ProjectApiImpl) UpdateSetting(ctx context.Context, req *project_api.UpdateSettingRequest) (*project_api.UpdateSettingResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.UpdateSettingResponse{
			Code:   project_api.UpdateSettingResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.UpdateSettingResponse{
			Code:   project_api.UpdateSettingResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.UpdateSettingResponse{
			Code:   project_api.UpdateSettingResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if projectItem.Closed {
		return &project_api.UpdateSettingResponse{
			Code:   project_api.UpdateSettingResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_api.UpdateSettingResponse{
			Code:   project_api.UpdateSettingResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//更新信息
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ProjectInfoDao.UpdateSetting(sessCtx, req.ProjectId, &project_dao.SettingDbItem{
			HideCustomEvent:          req.Setting.HideCustomEvent,
			HideCustomEventForAdmin:  req.Setting.HideCustomEventForAdmin,
			ShowRequireMentListEntry: req.Setting.ShowRequireMentListEntry,
			ShowTaskListEntry:        req.Setting.ShowTaskListEntry,
			ShowBugListEntry:         req.Setting.ShowBugListEntry,
			ShowTestCaseListEntry:    req.Setting.ShowTestCaseListEntry,
		})
		if err != nil {
			return nil, err
		}
		return &project_api.UpdateSettingResponse{
			Code: project_api.UpdateSettingResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateProjectNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_api.UpdateSettingResponse), nil
}

func (apiImpl *ProjectApiImpl) UpdateTipList(ctx context.Context, req *project_api.UpdateTipListRequest) (*project_api.UpdateTipListResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.UpdateTipListResponse{
			Code:   project_api.UpdateTipListResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.UpdateTipListResponse{
			Code:   project_api.UpdateTipListResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.UpdateTipListResponse{
			Code:   project_api.UpdateTipListResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if projectItem.Closed {
		return &project_api.UpdateTipListResponse{
			Code:   project_api.UpdateTipListResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_api.UpdateTipListResponse{
			Code:   project_api.UpdateTipListResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//更新信息
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ProjectInfoDao.UpdateTipList(sessCtx, req.ProjectId, req.TipList)
		if err != nil {
			return nil, err
		}
		return &project_api.UpdateTipListResponse{
			Code: project_api.UpdateTipListResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateProjectNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_api.UpdateTipListResponse), nil
}

func (apiImpl *ProjectApiImpl) Get(ctx context.Context, req *project_api.GetRequest) (*project_api.GetResponse, error) {
	emptyInfo := &project_api.ProjectInfo{
		BasicInfo:       &project_api.BasicProjectInfo{},
		UserProjectPerm: &project_api.UserProjectPerm{},
	}
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.GetResponse{
			Code:   project_api.GetResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Info:   emptyInfo,
		}, nil
	}
	memberItem, err := project_dao.MemberInfoDao.Get(ctx, req.ProjectId, sessionItem.UserId)
	if err != nil {
		return &project_api.GetResponse{
			Code:   project_api.GetResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Info:   emptyInfo,
		}, nil
	}
	memberItemMap := map[string]*project_dao.MemberInfoDbItem{
		req.ProjectId: memberItem,
	}

	infoItem, err := project_dao.ProjectInfoDao.Get(ctx, req.ProjectId)
	if err != nil {
		return &project_api.GetResponse{
			Code:   project_api.GetResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			Info:   emptyInfo,
		}, nil
	}
	//获取角色信息
	roleItemList, err := project_dao.MemberRoleDao.ListByProjectId(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	roleItemMap := map[string]*project_dao.RoleInfoDbItem{}
	for _, roleItem := range roleItemList {
		roleItemMap[roleItem.RoleId] = roleItem
	}
	userProjectPerm := apiImpl.calcUserProjectPerm(ctx, infoItem, sessionItem.UserId, memberItemMap, roleItemMap)
	info := infoItem.ToProjectInfo(userProjectPerm)
	//补充成员信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{infoItem.OwnerUserId})
	if err != nil {
		return nil, err
	}
	if len(userItemList) > 0 {
		info.OwnerDisplayName = userItemList[0].BasicInfo.DisplayName
		info.OwnerLogoUri = userItemList[0].BasicInfo.LogoUri
	}
	return &project_api.GetResponse{
		Code: project_api.GetResponse_CODE_OK,
		Info: info,
	}, nil
}

func (apiImpl *ProjectApiImpl) List(ctx context.Context, req *project_api.ListRequest) (*project_api.ListResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.ListResponse{
			Code:   project_api.ListResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	myProjectList, err := project_dao.MemberInfoDao.ListMyProject(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	projectIdList := []string{}
	myProjectWeightMap := map[string]uint32{}
	for _, myProject := range myProjectList {
		projectIdList = append(projectIdList, myProject.ProjectId)
		myProjectWeightMap[myProject.ProjectId] = myProject.ProjectWeight
	}
	infoItemList, err := project_dao.ProjectInfoDao.ListById(ctx, projectIdList, req.FilterClosed, req.Closed)
	if err != nil {
		return nil, err
	}

	//获取在所在项目的成员信息
	memberItemList, err := project_dao.MemberInfoDao.ListMemberByProjectAndUser(ctx, projectIdList, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	//key是项目ID
	memberItemMap := map[string]*project_dao.MemberInfoDbItem{}
	for _, memberItem := range memberItemList {
		memberItemMap[memberItem.ProjectId] = memberItem
	}

	//获取角色信息
	roleItemList, err := project_dao.MemberRoleDao.ListByProjectIdList(ctx, projectIdList)
	if err != nil {
		return nil, err
	}
	roleItemMap := map[string]*project_dao.RoleInfoDbItem{}
	for _, roleItem := range roleItemList {
		roleItemMap[roleItem.RoleId] = roleItem
	}
	//补充成员信息
	userIdList := []string{}
	for _, infoItem := range infoItemList {
		userIdList = append(userIdList, infoItem.OwnerUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	infoList := []*project_api.ProjectInfo{}
	for _, infoItem := range infoItemList {
		userProjectPerm := apiImpl.calcUserProjectPerm(ctx, infoItem, sessionItem.UserId, memberItemMap, roleItemMap)
		info := infoItem.ToProjectInfo(userProjectPerm)
		userItem, ok := userItemMap[infoItem.OwnerUserId]
		if ok {
			info.OwnerDisplayName = userItem.BasicInfo.DisplayName
			info.OwnerLogoUri = userItem.BasicInfo.LogoUri
		}
		info.MyWeight = myProjectWeightMap[infoItem.ProjectId]
		infoList = append(infoList, info)
	}
	sort.Sort(sort.Reverse(ProjectList(infoList)))
	return &project_api.ListResponse{
		Code:     project_api.ListResponse_CODE_OK,
		InfoList: infoList,
	}, nil
}

func (apiImpl *ProjectApiImpl) calcUserProjectPerm(ctx context.Context,
	projectItem *project_dao.ProjectInfoDbItem,
	userId string,
	memberItemMap map[string]*project_dao.MemberInfoDbItem,
	roleItemMap map[string]*project_dao.RoleInfoDbItem) *project_api.UserProjectPerm {
	if projectItem.OwnerUserId == userId {
		canOpen := false
		canClose := false
		if projectItem.Closed {
			canOpen = true
		} else {
			canClose = true
		}
		return &project_api.UserProjectPerm{
			CanOpen:         canOpen,
			CanClose:        canClose,
			CanUpdate:       true,
			CanAddMember:    true,
			CanRemoveMember: true,
			CanLeave:        false,
			CanAdmin:        true,
			CanRemove:       canOpen,
		}
	} else {
		memberItem, ok := memberItemMap[projectItem.ProjectId]
		if !ok {
			return &project_api.UserProjectPerm{}
		}
		roleItem, ok := roleItemMap[memberItem.RoleId]
		if !ok {
			return &project_api.UserProjectPerm{}
		}
		canOpen := false
		canClose := false
		if projectItem.Closed {
			if roleItem.BasicInfo.Admin {
				canOpen = true
			}
		} else {
			if roleItem.BasicInfo.Admin {
				canClose = true
			}
		}
		return &project_api.UserProjectPerm{
			CanOpen:         canOpen,
			CanClose:        canClose,
			CanUpdate:       roleItem.BasicInfo.Admin,
			CanAddMember:    roleItem.BasicInfo.Admin,
			CanRemoveMember: roleItem.BasicInfo.Admin,
			CanLeave:        true,
			CanAdmin:        roleItem.BasicInfo.Admin,
			CanRemove:       false,
		}
	}
}

func (apiImpl *ProjectApiImpl) Open(ctx context.Context, req *project_api.OpenRequest) (*project_api.OpenResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.OpenResponse{
			Code:   project_api.OpenResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.OpenResponse{
			Code:   project_api.OpenResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.OpenResponse{
			Code:   project_api.OpenResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if !projectItem.Closed {
		return &project_api.OpenResponse{
			Code:   project_api.OpenResponse_CODE_ALLREADY_OPEN,
			ErrMsg: "项目是打开状态",
		}, nil
	}
	if !roleItem.BasicInfo.Admin {
		return &project_api.OpenResponse{
			Code:   project_api.OpenResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := project_dao.ProjectInfoDao.UpdateCloseFlag(sessCtx, req.ProjectId, false)
		if err != nil {
			return nil, err
		}
		return &project_api.OpenResponse{
			Code: project_api.OpenResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	go apiImpl.addOpenEvent(sessionItem, req, projectItem)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateProjectNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_api.OpenResponse), nil
}

func (apiImpl *ProjectApiImpl) Close(ctx context.Context, req *project_api.CloseRequest) (*project_api.CloseResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.CloseResponse{
			Code:   project_api.CloseResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.CloseResponse{
			Code:   project_api.CloseResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.CloseResponse{
			Code:   project_api.CloseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_api.CloseResponse{
			Code:   project_api.CloseResponse_CODE_ALLREADY_CLOSE,
			ErrMsg: "项目是关闭状态",
		}, nil
	}
	if !roleItem.BasicInfo.Admin {
		return &project_api.CloseResponse{
			Code:   project_api.CloseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ProjectInfoDao.UpdateCloseFlag(sessCtx, req.ProjectId, true)
		if err != nil {
			return nil, err
		}
		err = project_dao.MemberInfoDao.UpdateProjectWeight(sessCtx, req.ProjectId, sessionItem.UserId, 0)
		if err != nil {
			return nil, err
		}
		return &project_api.CloseResponse{
			Code: project_api.CloseResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	go apiImpl.addCloseEvent(sessionItem, req, projectItem)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateProjectNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_api.CloseResponse), nil
}

func (apiImpl *ProjectApiImpl) Remove(ctx context.Context, req *project_api.RemoveRequest) (*project_api.RemoveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.RemoveResponse{
			Code:   project_api.RemoveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.RemoveResponse{
			Code:   project_api.RemoveResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.RemoveResponse{
			Code:   project_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if !projectItem.Closed {
		return &project_api.RemoveResponse{
			Code:   project_api.RemoveResponse_CODE_NOT_CLOSE,
			ErrMsg: "项目需要处于关闭状态",
		}, nil
	}
	if sessionItem.UserId != projectItem.OwnerUserId {
		return &project_api.RemoveResponse{
			Code:   project_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//列出现有用户
	memberItemList, err := project_dao.MemberInfoDao.ListMember(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.MemberInfoDao.RemoveByProject(sessCtx, req.ProjectId)
		if err != nil {
			return nil, err
		}
		//清除project owner
		project_dao.ProjectInfoDao.ClearOwner(sessCtx, req.ProjectId)
		return &project_api.RemoveResponse{
			Code: project_api.RemoveResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addRemoveEvent(sessionItem, req, projectItem)
	//发送通知
	notice := &notices_project.RemoveProjectNotice{
		ProjectId: req.ProjectId,
	}
	for _, memberItem := range memberItemList {
		go api_common.SendNoticeToUser(context.Background(), memberItem.MemberUserId, notice)
	}
	return ret.(*project_api.RemoveResponse), nil
}

func (apiImpl *ProjectApiImpl) ChangeOwner(ctx context.Context, req *project_api.ChangeOwnerRequest) (*project_api.ChangeOwnerResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.ChangeOwnerResponse{
			Code:   project_api.ChangeOwnerResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.ChangeOwnerResponse{
			Code:   project_api.ChangeOwnerResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.ChangeOwnerResponse{
			Code:   project_api.ChangeOwnerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//必须是当前项目所有者才有权限设置owner
	if sessionItem.UserId != projectItem.OwnerUserId {
		return &project_api.ChangeOwnerResponse{
			Code:   project_api.ChangeOwnerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	exist, err := project_dao.MemberInfoDao.Exist(ctx, req.ProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_api.ChangeOwnerResponse{
			Code:   project_api.ChangeOwnerResponse_CODE_NO_MEMBER,
			ErrMsg: "项目成员不存在",
		}, nil
	}

	roleItemList, err := project_dao.MemberRoleDao.ListByProjectId(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//先转成管理员
		for _, roleItem := range roleItemList {
			if roleItem.BasicInfo.Admin {
				err = project_dao.MemberInfoDao.UpdateRole(sessCtx, req.ProjectId, req.MemberUserId, roleItem.RoleId)
				if err != nil {
					return nil, err
				}
				break
			}
		}
		//设置超管
		err = project_dao.ProjectInfoDao.SetOwner(sessCtx, req.ProjectId, req.MemberUserId, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_api.ChangeOwnerResponse{
			Code: project_api.ChangeOwnerResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	userItem, err := user_dao.UserInfoDao.Get(ctx, req.MemberUserId)
	if err == nil {
		go apiImpl.addChangeOwnerEvent(sessionItem, projectItem, userItem, nowTime)
	}
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateProjectNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_api.ChangeOwnerResponse), nil
}

func (apiImpl *ProjectApiImpl) SetWeight(ctx context.Context, req *project_api.SetWeightRequest) (*project_api.SetWeightResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_api.SetWeightResponse{
			Code:   project_api.SetWeightResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_api.SetWeightResponse{
			Code:   project_api.SetWeightResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_api.SetWeightResponse{
			Code:   project_api.SetWeightResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	if projectItem.Closed {
		return &project_api.SetWeightResponse{
			Code:   project_api.SetWeightResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.MemberInfoDao.UpdateProjectWeight(sessCtx, req.ProjectId, sessionItem.UserId, req.Weight)
		if err != nil {
			return nil, err
		}
		return &project_api.SetWeightResponse{
			Code: project_api.SetWeightResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_api.SetWeightResponse), nil
}
